<template>
  <section class="nb-table-wrapper">
    <el-collapse-transition>
      <div v-show='isShowSearch' class="search--wrapper">
        <el-button class='clearAll' type = 'text' @click='clearAll'>清除全部</el-button>
        <div class="list-item" v-for='(item, index) in searchList' @click='delItem(index, item)' :key='item.id'>
          <el-tooltip class="item" :hide-after="1500" effect="dark" :content="item.title + ':' + item.label" placement="top">
            <el-button type='text'>
              {{item.title}}:
              <el-button class='label-name' type='text'>{{item.label}}</el-button>
              <span class='close-span el-icon-close'></span>
            </el-button>
          </el-tooltip>
        </div>
      </div>
    </el-collapse-transition>
    <el-table
      :data="cloneData"
      :show-header="showHeader"
      border
      style="width: 100%;"
      tooltip-effect='dark'
      @select='selectRow'
      @select-all='selectRow'
      :class='{"el-table_radio": select === "radio"}'
      ref='table'
      :stripe="false"
      :height="heights"
      empty-text="没有查询到数据！"
    >
      <!--:style="{'height': tableHeight+'px'}"-->
      <el-table-column
        v-if="select"
        type='selection'
        :selectable="selectable"
        align="center"
        fixed="left"
        width="70">
      </el-table-column>
      <el-table-column
        v-if="operator || filterClickData(clickData).length"
        :fixed="operatorFixed"
        label="操作"
        :render-header="renderOperator"
        align="left"
        header-align='center'
        :width="fixedWidth">
        <template
          slot-scope="scope"
          v-if="filterClickData(clickData).length"
        >
          <el-button
            v-for="(item, index) in filterClickData(clickData, scope.row)"
            :key="index"
            @click="handleClick({row:scope.row, type:filterClickData(clickData, scope.row)[index].type})"
            type="text"
            style="padding:0 5px;margin-left: 10px; font-weight: 400;">
            {{filterClickData(clickData, scope.row)[index] && filterClickData(clickData, scope.row)[index].name}}
          </el-button>
        </template>
        <slot></slot>
      </el-table-column>
      <el-table-column
        v-for="(item, index) in _tableHeaders"
        :prop="item.headerKey"
        :min-width="item.width || defaultWidth"
        :key="item.headerKey"
        :align="align"
        :label="item.headerName"
        :fixed="item.fixed ? true : false"
        :render-header="renderHeader"
        :show-overflow-tooltip='true'
      >
        <template slot-scope="scope">
          <template v-if="item.hasOwnProperty('img')">
            <nb-img v-if="item.img.type || (item.img.value === scope.row[item.img.key])" :url="item.img.url" width="12"></nb-img>
          </template>
          <a v-if="item.click" type="text" @click.stop="clickFirst(scope.row, item)">
            {{formatRow(scope.row, item)}}
            <nb-badge v-if="item.badge" :row="scope.row" :badge="item.badge"></nb-badge>
          </a>
          <template v-else-if="item.ableInput">
            <el-input style="width: 70%; margin-right: 10px;" @input="changeInput" v-model="scope.row[item.headerKey]"></el-input>
            {{item.tips}}
          </template>
          <template v-else>
            {{formatRow(scope.row, item) === '-1' ? '' : formatRow(scope.row, item)}}
            <nb-badge v-if="item.badge" :row="scope.row" :badge="item.badge"></nb-badge>
          </template>
        </template>
      </el-table-column>
    </el-table>
    <el-dialog :append-to-body="true" class="transfer-wrapper" @close="closeFields" title="编辑显示字段" :visible.sync="fieldVisible">
      <el-transfer v-model="fields" :data="allFields"></el-transfer>
      <!--<nb-transfer v-model="fields" :data="allFields"></nb-transfer>-->
      <!-- <div class='dialog-footer' slot="footer">
        <nb-button large type="plain"  @click="resetBack">恢复默认</nb-button>
        <nb-button large  type="primary" @click="saveEdit">保存设置</nb-button>
      </div> -->
    </el-dialog>
  </section>
</template>

<script>
  import {Dropdown, DropdownMenu, DropdownItem, CollapseTransition, Tooltip} from 'element-ui'
  import {cloneDeep, isEqual} from 'lodash'
  import {formatTable, mergeHeader, fieldArr} from '@/common/utils'
  import Transfer from '@/components/field-transfer'
  import NbTransfer from '@/components/nb-transfer'
  import NbBadge from './nb-table-badge.vue'
  /**
   * table vue 组件
   * 包含的功能有：可选择CheckBox（可选）、第一列固定（可选）、操作列表固定
   * 操作列表按钮、表格宽度、表格内数据过滤。可定制
   * 第一列可定制点击事件
   * 最后一列可定制点击事件
   * table所要显示的列可定制
   *
   * tableHeaders 数组 显示表头字段
   * tableData 数组 table数据
   * select String 是否可选择 支持单选  规则：select 为select时 多选   select 为 radio时 单选 点击选择按钮时，都返回selectRow事件
   * 参数为selected数组、当前点击行数据；全选或取消全选时无第二个参数
   * fixedOne Boolean 第一列是否固定
   * clickData 数组 右侧按钮定制数组对象 并返回clickRight 事件 父组件来监听
   * minWidth 表格宽度
   * format 表格内数据过滤规则格式[{need:'需要过滤的字段', type:'对应的过滤规则名称'}]
   * 规则名称目前有 phone card date（可传时间模板 'date|YYYY-MM-DD HH:mm:ss'）
   * align 表格内对齐方式 left/center/right
   * headerMap 该数组对象中包含了搜索、数据过滤、添加标签、列表可点击，这个对象对于表头列表非接口返回的情况下不需要传递，这些相应的功能
   * 直接写到tableHeaders数组对象中；对于表头列表为接口返回的情况下，需要传递该对象，这个对象会混合到tableHeaders 中
   * headerMap: [{
   *  headerKey: 'statusKey'
   *  searchKey: 'status', 对应搜索字段 当搜索字段与headerKey相同的时候不需要这个字段
   *  headerName: '状态',
   *  headerType: 'select', 搜索类型  input输入框 select选择框 sort排序
   *  options: [{           options对应select 的列表
   *    label: '待审核',
   *    value: '0'
   *  }, {
   *    label: '审核通过',
   *    value: '1'
   *  }, {
   *    label: '账号禁用',
   *    value: '2'
   *  }, {
   *    label: '审核不通过',
   *    value: '99'
   *  }],
   *  click: true,        click为true时可点击  返回事件clickFirst
   *  type: 'phone| card| date',   表格列表过滤类型
   *  badge: {            表格字段标记
   *    name: '',
   *    key: '',
   *    value: ''
   *  },
   *  img: {          // 有img对象属性  就会显示图片
   *    url: '',      // 图片地址
   *    type: true/false, // true 直接显示 false 根据下面条件显示  即：当相对应的key参数=== value时显示
   *    key: '',
   *    value: ''
   *  }
   * }]
   * queryModel 查询列表数据对象 用来点击删除搜索条件，对相应的字段置空，并返回该对象，注：父组件需要delQueryModel方法来接收数据
   * defaultWidth 默认宽度
   * fixd: header入参中添加key值，固定列设置为true
   */
  export default {
    data () {
      return {
        widthMap: {
          1: '80',
          2: '160',
          3: '240',
          4: '320',
          5: '400'
        },
        nameReg: /set-box|fa/,
        fieldVisible: false,
        data: [],
        value1: [],
        allFields: this.allField,
        fields: this.field,
        cloneField: cloneDeep(this.field),
        sortFlag: true,
        searchList: [],
        headerMaps: this.headerMap,
        tableRadio: '',
        tableHeight: 0,
        cloneHeaders: this.tableHeaders,
        cloneData: this.tableData,
        cloneRow: null,
        target: null
      }
    },
    props: {
      tableHeaders: {
        type: Array,
        default: () => []
      },
      tableData: {
        type: Array,
        default: () => []
      },
      select: String,
      radio: Boolean,
      fixedOne: {
        type: Boolean,
        default: true
      },
      clickData: {
        type: Array,
        default: () => []
      },
      clickDataWidth: {
        type: String,
        default: ''
      },
      minWidth: {
        type: String,
        default: '180'
      },
      format: {
        type: Array,
        default: () => []
      },
      operator: Boolean,
      align: {
        type: String,
        default: 'left'
      },
      allField: Array,
      field: Array,
      headerMap: {
        type: Array,
        default: () => []
      },
      queryModel: Object,
      defaultWidth: {
        type: String,
        default: '155'
      },
      showHeader: {
        type: Boolean,
        default: true
      },
      popDisabled: Boolean,
      height: String,
      top: {
        type: Number,
        default: 0
      },
      operatorText: Boolean, // 表头右侧是否显示操作文案
      operatorFixed: {
        type: String,
        default: 'right'
      }
    },
    watch: {
      tableHeaders (val) {
        this.cloneHeaders = val
      },
      tableData (val) {
        this.cloneData = val
      },
      allField () {
        this.allFields = this.allField
      },
      field () {
        this.fields = this.field
        this.cloneField = cloneDeep(this.field)
      },
      headerMap () {
        this.headerMaps = this.headerMap
      },
      $router () {
      },
      searchList () {
      }
    },
    components: {
      ElDropdownMenu: DropdownMenu,
      ElDropdownItem: DropdownItem,
      ElDropdown: Dropdown,
      ElTransfer: Transfer,
      ElCollapseTransition: CollapseTransition,
      ElTooltip: Tooltip,
      NbTransfer,
      NbBadge
    },
    computed: {
      fixedWidth () {
        if (this.clickDataWidth) {
          return this.clickDataWidth
        } else {
          let l = this.clickData.length
          return this.widthMap[l] || '100'
        }
      },
      _tableHeaders () {
        let header = cloneDeep(this.cloneHeaders)
        mergeHeader(header, this.headerMaps)
        return header
      },
      isShowSearch () {
        return this.searchList.length > 0
      },
      heights () {
        if (this.tableData.length > 0) {
          return this.height === 'auto' ? this.isShowSearch ? this.tableHeight - 60 : this.tableHeight : this.height ? this.height : ''
        } else {
          // return document.body.clientHeight - 180
          return 500
        }
      }
    },
    methods: {
      getData () {
        return this.cloneData
      },
      clickFirst (value, item) {
        this.$emit('clickFirst', value, item)
      },
      handleClick (data) {
        this.$emit('clickRight', data)
      },
      formatRow (row, key) {
        if (key.hasOwnProperty('type')) {
          let type = key.type.split('|')
          return (formatTable[type[0]](row[key.headerKey], type[1]) + (key.tips || '')) || ''
        }
        if (key.hasOwnProperty('rules')) {
          let text = row[key.rules.key] === key.rules.value ? key.rules.success : key.rules.error
          return (row[key.headerKey] && (row[key.headerKey] + text)) || ''
        }
        if (key.hasOwnProperty('joint')) {
          let allValue = ''
          let jointValue = key.joint.map((val, index) => {
            allValue = allValue + (row[val] || '')
            return allValue
          })
          return jointValue.length && jointValue[(jointValue.length - 1)]
        }
        if (key.hasOwnProperty('fun')) {
          return key.fun(row)
        }
        // 空值直接不显示
        return (row[key.headerKey] && (row[key.headerKey] + (key.tips || '')))
      },
      headerClick () {
        this.fieldVisible = true
        this.$emit('operator')
      },
      renderOperator () {
        if (this.operator) {
          return (
            <div
              class="set-box"
              onClick={this.headerClick.bind(this)}
            >
              <span class="fa fa-cog" style="font-size: 20px; cursor: pointer;"></span>
            </div>
          )
        } else if (this.operatorText) {
          return (
            <div class="set-box">
              操作
            </div>
          )
        } else {
          return (
            <div class="set-box">
            </div>
          )
        }
      },
      renderHeader (h, {$index}) {
        if (this.operatorFixed === 'left') {
          $index = this.select ? $index - 2 : $index - 1
        } else {
          $index = this.select ? $index - 1 : $index
        }
        let row = this._tableHeaders[$index]
        if (!row.hasOwnProperty('headerType')) {
          return (
            <div class="header-wrapper">
              {row.headerName}
            </div>
          )
        } else {
          return (
            <div class="header-wrapper">
              {row.headerName}
              <nb-popover data={JSON.stringify(row)}></nb-popover>
            </div>
          )
        }
      },
      checkDropdown (index, item, row) {
        let flag = false
        if (item.value === true) {
          flag = row[item.key]
        } else {
          flag = row[item.key] === item.value
        }
        return (index > 0) && flag
      },
      filterClickData (data, row) {
        let _data = cloneDeep(data)
        let __data = _data.filter(item => {
          if (item.disabled) {
            return false
          } else if (!item.hasOwnProperty('key')) {
            return true
          } else if (row) {
            if (item.value === true) {
              return row[item.key]
            } else if (item.sym) {
              return row[item.key] !== item.value
            } else {
              return row[item.key] === item.value
            }
          } else {
            return true
          }
        })
        return __data
      },
      saveEdit () {
        this.$store.commit('DELETE_FIELD')
        let f = fieldArr(this.fields)
        this.cloneHeaders = []
        this.cloneData = []
        this.$emit('saveField', f)
        this.fieldVisible = false
      },
      resetBack () {
        this.$store.commit('DELETE_FIELD')
        this.cloneHeaders = []
        this.cloneData = []
        this.fieldVisible = false
        this.$emit('resetField')
      },
      closeFields () {
        this.fields = this.cloneField
      },
      selectRow (selection, row) {
        if (this.select === 'radio') {
          this.$refs.table.clearSelection()
          if (isEqual(row, this.cloneRow)) {
            this.cloneRow = null
            this.$emit('selectRow', [], {})
          } else {
            this.cloneRow = row
            this.$refs.table.toggleRowSelection(row)
            this.$emit('selectRow', row ? [row] : [], row)
          }
        } else {
          this.$emit('selectRow', selection, row)
        }
      },
      setSelect (row) {
        row.forEach(item => {
          this.$refs.table.toggleRowSelection(item)
        })
      },
      clearAll () {
        this.searchList.map(item => {
          if (item.type === 'sort') {
            this.queryModel.orderBy = ''
          }
          this.queryModel.param[item.key] = ''
        })
        this.searchList = []
        this.target.delQueryModel(this.queryModel, {type: 'all'})
      },
      delItem (index, item) {
        this.searchList.splice(index, 1)
        if (item.type === 'sort') {
          this.queryModel.orderBy = ''
        } else {
          this.queryModel.param[item.key] = ''
        }
        this.target.delQueryModel(this.queryModel, item)
      },
      handleSearchPop (value, row, type) {
        if (type === 'sort') {
          value = value === 1 ? '升序' : '降序'
        } else if (type === 'daterange' || type === 'range' || type === 'moreSearch') {
          value = `${value[0]} - ${value[1]}`
        }
        let flag = false
        this.searchList.map(item => {
          if (type === 'sort') {
            if (item.type === 'sort') {
              flag = true
              item.title = row.headerName
              item.label = value
              item.type = type || ''
              item.key = row.searchKey || row.headerKey
              item.id = row.headerName + value
            }
          } else if (item.title === row.headerName && item.type !== 'sort') {
            flag = true
            item.label = value
            item.type = type || ''
            item.key = row.searchKey || row.headerKey
            item.id = row.headerName + value
          }
        })
        if (!flag) {
          this.searchList.push({
            title: row.headerName,
            label: value,
            type: type || '',
            key: row.searchKey || row.headerKey,
            id: row.headerName + value
          })
        }
      },
      onResize () {
        let that = this
        let height = document.documentElement.clientHeight || document.body.clientHeight
        this.tableHeight = height - 114 - 60 - this.top
        window.onresize = () => {
          height = document.documentElement.clientHeight || document.body.clientHeight
          that.$emit('resize', height)
          that.tableHeight = height - 114 - 60 - this.top
        }
      },
      selectable (row, index) { // 判断是否可以勾选
        if (row.scope === 0 || row.scope > 0) {
          return false
        } else {
          return true
        }
      },
      findTarget (t) {
        if (t.delQueryModel && t.delQueryModel) {
          this.target = t
        } else {
          this.findTarget(t.$parent)
        }
      },
      changeInput () {
        this.$emit('change')
      }
    },
    destroyed () {
      this.$root.event.$off('cancelSelect')
    },
    mounted () {
      if (!this.popDisabled) {
        this.findTarget(this)
      }
      this.$nextTick(() => {
        if (this.height === 'auto') {
          this.onResize()
        }
      })
      this.$root.event.$on('cancelSelect', () => {
        this.tableRadio = ''
        this.$refs.table.clearSelection()
      })
    }
  }
</script>

<style lang="scss">
.set-box{
  width: 100%;
  cursor: pointer;
  padding: 0 !important;
  position: relative;
  top: 6px;
  span{
    color: #878d99 !important;
    transition: all 0.2s linear;
  }
}
.set-box:hover{
  span{
    color: #409eff !important;
  }
}
.transfer-wrapper{
  .el-dialog{
    width: 546px;
    .el-dialog__body{
      padding: 0;
    }
  }
}
.header-wrapper{
  width: 100%;
  padding: 0 !important;
  position: relative;
  top: 4px;
  .el-icon-caret-bottom, .el-icon-caret-top{
    cursor: pointer;
  }
}
.search--wrapper{
  display: flex;
  padding: 10px;
  align-items: center;
  flex-wrap: wrap;
  transition: all 0.2s linear;
  .clearAll{
    margin-left: 10px;
  }
  .list-item{
    border: 1px solid #ddd;
    font-size: 12px;
    margin: 4px 10px ;
    height: 30px;
    line-height: 30px;
    padding-left: 8px;
    border-radius: 4px;
    overflow: hidden;
    color: #999;
    cursor: pointer;
    button{
      font-size: 12px;
      padding: 0;
      color: #999;
      .label-name{
        color: #409eff;
      }
    }
    .close-span{
      padding: 10px;
      margin-left: 5px;
      cursor: pointer;
    }
  }
  .list-item:hover{
    border: 1px solid #409eff;
    .close-span{
      color: #fff;
      background: #409eff;
      white-space: normal;
    }
  }
}
.el-table_radio{
  .el-checkbox__inner{
    border-radius: 50%;
  }
  .el-table__fixed-header-wrapper{
    .el-checkbox{
      display: none;
    }
  }
}
.row-radio{
  width: 14px;
  overflow: hidden;
  margin: 0 auto;
}
  .nb-table-wrapper{
    /*height: 500px;*/
    /*outline: 1px solid blue;*/
    position: relative;
    .mark-nb-table{
      top: -2px;
    }
  }
  .nb-table-wrapper:after{
    left: 0px;
    position: absolute;
    content: '';
    top: 0;
    height: 100%;
    width: 1px;
    background: #e6ebf5;
    z-index: 999;
  }
</style>
